#include"Task.hpp"
#include<string>
#include<unistd.h>
#include<cassert>
#include<time.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<sys/stat.h>

#define ProcessNum 10
std::vector<task_t> tasks;
//先描述再组织
class channel
{
public:
    channel(int cmdfd,pid_t slaverid,std::string processname)
        :_cmdfd(cmdfd)
        ,_slaverid(slaverid)
        ,_processname(processname)
        {}
public:
    int _cmdfd;               // 发送任务的文件描述符
    pid_t _slaverid;          // 子进程pid
    std::string _processname; // 子进程的名字，方便我们打日志
};

void Slaver()
{
    //read
    while(true)
    {
        int commandcode=0;
        int n=read(0,&commandcode,sizeof(int));
        if(n==sizeof(int))
        {
            //输送
            std::cout<<"slaver say@ get a command "<<getpid()<<" commandcode: "<<commandcode<<std::endl;
            if(commandcode>=0&&commandcode<tasks.size()) tasks[commandcode]();
        }
        if(n==0) break;
    }

}

//
void InitProcess(std::vector<channel>* channels)
{
    std::vector<int> oldfd;
     for(int i=0;i<ProcessNum;i++)
    {
        int pipefd[2]={0};
        int n=pipe(pipefd);
        // 判断管道是否创建成功
        assert(!n);
        (void)n;
        pid_t id=fork();
        if(id<0)
        {
            perror("fork");
            return;
        }
        else if(id==0) //child
        {
            for(auto&fd:oldfd)
            {
                // std::cout<<fd<<" ";
                close(fd);
            }
            std::cout<<std::endl;

            close(pipefd[1]);
            dup2(pipefd[0],0);
            close(pipefd[0]);
            Slaver();
            exit(0);
        }
        //father
        close(pipefd[0]);
        //添加channel字段了
        std::string name="process"+std::to_string(i);
        channels->push_back(channel(pipefd[1],id,name));
        oldfd.push_back(pipefd[1]);
        //sleep(1);
    }
}

void Debug(const std::vector<channel>& channels)
{
    for(auto &c:channels)
    {
        std::cout<<c._slaverid<<" : "<<c._processname<<" : "<<c._cmdfd<<std::endl;
    }
}

extern void Menu();

void ctrlSlaver(const std::vector<channel> &channels)
{
    while (true)
    {  
        int select=0;
        Menu();
        std::cin>>select;
        if(select<=0 ||select>=5) break;
        // 选择任务
        // int commandcode = rand() % tasks.size();
        int commandcode=select-1;
        // 选择进程
        int processpos = rand() % channels.size();
        // 发送任务
        std::cout << "father say@ " << " commandcode" << commandcode << " already send to " << " process name " << channels[processpos]._processname << std::endl;
        write(channels[processpos]._cmdfd, &commandcode, sizeof(commandcode));
        sleep(1);
    }
}

void Menu()
{
    std::cout << "####################################################################" << std::endl;
    std::cout << "####################################################################" << std::endl;
    std::cout << "#######1.检查单词是否有问题    2.检查是否要更新版本###################" << std::endl;
    std::cout << "#######3. 查看下载进度   4.查看用户是否需要登录#######################" << std::endl;
    std::cout << "##########0.退出####################################################" << std::endl;
    std::cout << "####################################################################" << std::endl;
} 


void QuitProcess(const std::vector<channel> &channels)
{
    // version2
    for(auto& c:channels)
    {
        close(c._cmdfd);
        waitpid(c._slaverid,nullptr,0);
    }
    //version1
    // int last=channels.size()-1;
    // for(int i=last;i>0;i--)
    // {
    //     close(channels[i]._cmdfd);
    //     waitpid(channels[i]._slaverid,nullptr,0);
    // }
}

int main()
{
    LoadTask(&tasks);
    srand(time(nullptr)^2022);
    //再组织
    std::vector<channel> channels;
    //初始化，创建多个进程…………建框架
   InitProcess(&channels);
    Debug(channels);
    //控制子进程
    ctrlSlaver(channels);

    //清理收尾
    QuitProcess(channels);
    return 0;
}